package org.pluslibs.framework.swingplus.utils;

import java.awt.Dimension;
import java.awt.Frame;
import java.awt.GraphicsDevice;
import java.awt.GraphicsEnvironment;
import java.awt.Rectangle;
import java.awt.Toolkit;
import java.awt.event.KeyEvent;

import javax.swing.AbstractAction;
import javax.swing.InputMap;
import javax.swing.JComponent;
import javax.swing.KeyStroke;
import javax.swing.UIManager;

/**
 * GUI utilites; centers components to screen mainly
 */
public class SwingUtils {

    public static Frame getTopFrame() {
        Frame[] frames = Frame.getFrames();
        for(int i = 0; i < frames.length; i++) {
            if(frames[i].getFocusOwner() != null) {
                return frames[i];
            }
        }
        if(frames.length > 0) {
            return frames[0];
        }
        return null;
    }
    /* *********************************************** */
    // Don't allow instantiation

    private SwingUtils() { }

    public static void beep() {
        Toolkit.getDefaultToolkit().beep();
    }

    /* *********************************************** */
    // Key Listeners

    public static void addGlobalKey_Ctrl(JComponent component, int keyevent, AbstractAction action) {
        addGlobalKey(component, keyevent, KeyEvent.CTRL_DOWN_MASK, action);
    }
    public static void addGlobalKey_Alt(JComponent component, int keyevent, AbstractAction action) {
        addGlobalKey(component, keyevent, KeyEvent.ALT_DOWN_MASK, action);
    }
    public static void addGlobalKey_CtrlAlt(JComponent component, int keyevent, AbstractAction action) {
        addGlobalKey(component, keyevent, KeyEvent.CTRL_DOWN_MASK | KeyEvent.ALT_DOWN_MASK, action);
    }
    private static void addGlobalKey(JComponent component, int keyevent, int modifiers, AbstractAction action) {
        InputMap inputmap = component.getInputMap(JComponent.WHEN_IN_FOCUSED_WINDOW);
        inputmap.put(KeyStroke.getKeyStroke(keyevent, modifiers), action);
        component.getActionMap().put(action, action);
    }
    public static void addGlobalKey_Help(JComponent component, AbstractAction action) {
        InputMap inputmap = component.getInputMap(JComponent.WHEN_IN_FOCUSED_WINDOW);
        inputmap.put(KeyStroke.getKeyStroke(KeyEvent.VK_F1,   0), action);
        inputmap.put(KeyStroke.getKeyStroke(KeyEvent.VK_HELP, 0), action);
        component.getActionMap().put(action, action);
    }

    /* *********************************************** */
    // Window size/positioning

    /**
     * Returns the screensize to the caller
     */
    public static java.awt.Dimension getScreenSize() {
        java.awt.Toolkit toolkit = java.awt.Toolkit.getDefaultToolkit();
        return toolkit.getScreenSize();
    }

    /**
     * Center component on screen
     */
    public static void centerScreen(java.awt.Component c) {
        java.awt.Dimension dim = c.getToolkit().getScreenSize();
        java.awt.Rectangle abounds = c.getBounds();
        c.setLocation((dim.width - abounds.width) / 2, (dim.height - abounds.height) / 2);
    }
    public static void centerScreen(java.awt.Component c, int width, int height) {
        // Resize and center on screen
        java.awt.Dimension dim = c.getToolkit().getScreenSize();
        c.setBounds((dim.width-width)/2, (dim.height-height)/2, width, height);
    }

    public static void topRightSecondaryScreen(java.awt.Component c, int width, int height) {
        GraphicsDevice device = getSecondaryMonitor();
        Rectangle bounds = device.getDefaultConfiguration().getBounds();
        if ( width >bounds.width  ) width  = bounds.width;
        if ( height>bounds.height ) height = bounds.height;
        c.setBounds(bounds.x+bounds.width-width, bounds.y, width, height);
    }
    public static void centerSecondaryScreen(java.awt.Component c, int width, int height) {
        GraphicsDevice device = getSecondaryMonitor();
        Rectangle bounds = device.getDefaultConfiguration().getBounds();
        if ( width >bounds.width  ) width  = bounds.width;
        if ( height>bounds.height ) height = bounds.height;
        c.setBounds(bounds.x + (bounds.width-width)/2, bounds.y + (bounds.height-height)/2, width, height);
    }
    public static void topSecondaryScreen(java.awt.Component c, int width, int height) {
        GraphicsDevice device = getSecondaryMonitor();
        Rectangle bounds = device.getDefaultConfiguration().getBounds();
        if ( width >bounds.width  ) width  = bounds.width;
        if ( height>bounds.height ) height = bounds.height;
        c.setBounds(bounds.x + (bounds.width-width)/2, 0, width, height);
    }
    private static GraphicsDevice getSecondaryMonitor() {
        GraphicsEnvironment environment = GraphicsEnvironment.getLocalGraphicsEnvironment();
        GraphicsDevice defaultdevice = environment.getDefaultScreenDevice();
        for ( GraphicsDevice device : environment.getScreenDevices() ) {
            if ( device==defaultdevice ) continue;
            return device;
        }
        return defaultdevice;
    }

    public static void packEnsureMargin(java.awt.Window w, int margin_width, int margin_height, int extra_width, int extra_height) {
        w.pack();
        Dimension bounds = w.getSize();
        Dimension screen = w.getToolkit().getScreenSize();

        // Adjust bounds if necessary
        boolean adjusted = false;
        if ( bounds.width+extra_width>screen.width-margin_width ) {
            adjusted = true;
            bounds.width = screen.width - margin_width;
        } else if ( extra_width>0 ) {
            adjusted = true;
            bounds.width += extra_width;
        }
        if ( bounds.height+extra_height>screen.height-margin_height ) {
            adjusted = true;
            bounds.height = screen.height - margin_height;
        } else if ( extra_height>0 ) {
            adjusted = true;
            bounds.height += extra_height;
        }
        if ( adjusted ) {
            w.setSize(bounds.width, bounds.height);
        }
    }

    /**
     * Center within parent component
     */
    public static void centerParent(java.awt.Component c) {
        // Find out our parent
        java.awt.Container myParent = c.getParent();
        if (myParent == null) {
            centerScreen(c);
        } else {
            try {
                java.awt.Point topLeft = myParent.getLocationOnScreen();
                java.awt.Dimension parentSize = myParent.getSize();
                java.awt.Dimension mySize = c.getSize();
                int center_x = topLeft.x + (parentSize.width/2) - (mySize.width/2);
                int center_y = topLeft.y + (parentSize.height/2) - (mySize.height/2);
                c.setLocation( center_x , center_y );
            } catch ( java.awt.IllegalComponentStateException e ) {
                // Exception occurs when the parent is not showing on the screen;
                //  in this case just center the other component to the screen.
                centerScreen(c);
            }
        }
    }
    public static void centerParent(java.awt.Component c, int width, int height) {
        // Find out our parent
        java.awt.Container myParent = c.getParent();
        if (myParent == null) {
            centerScreen(c, width, height);
        } else {
            try {
                java.awt.Point topLeft = myParent.getLocationOnScreen();
                java.awt.Dimension parentSize = myParent.getSize();
                int center_x = topLeft.x + (parentSize.width/2) - (width/2);
                int center_y = topLeft.y + (parentSize.height/2) - (height/2);
                c.setBounds(center_x, center_y, width, height);
            } catch ( java.awt.IllegalComponentStateException e ) {
                // Exception occurs when the parent is not showing on the screen;
                //  in this case just center the other component to the screen.
                centerScreen(c, width, height);
            }
        }
    }

    /* *********************************************** */
    // Look and Feel

    private static boolean isDefaultLookAndFeelEnabled = false;

    public static void ensureLookAndFeel() {
        if ( isDefaultLookAndFeelEnabled ) return;
        setLookAndFeel();
        isDefaultLookAndFeelEnabled = true;
    }

    /**
     * Sets the system default look and feel
     */
    public static void setLookAndFeel() {
        String lookandfeel = UIManager.getSystemLookAndFeelClassName();
        try {
            UIManager.setLookAndFeel( lookandfeel );
        } catch ( Throwable e) {
            e.printStackTrace();
        }
    }
    public static void setLookAndFeelNimbus() {
        setLookAndFeel( "com.sun.java.swing.plaf.nimbus.NimbusLookAndFeel" );
    }
    public static void setLookAndFeelMetalDefault() {
        setLookAndFeel( "javax.swing.plaf.metal.MetalLookAndFeel" );
        javax.swing.plaf.metal.MetalLookAndFeel.setCurrentTheme(new javax.swing.plaf.metal.DefaultMetalTheme());
    }
    public static void setLookAndFeelMetalOcean() {
        setLookAndFeel( "javax.swing.plaf.metal.MetalLookAndFeel" );
        javax.swing.plaf.metal.MetalLookAndFeel.setCurrentTheme(new javax.swing.plaf.metal.OceanTheme());
    }
    public static void setLookAndFeel(String lookandfeel) {
        if ( lookandfeel==null ) throw new NullPointerException();
        try {
            UIManager.setLookAndFeel( lookandfeel );
        } catch ( Throwable e) {
            // Print error message
            e.printStackTrace();

            // Attempt to set default system look and feel if not
            String defaultlookandfeel = UIManager.getSystemLookAndFeelClassName();
            if ( lookandfeel!=null && defaultlookandfeel!=null && lookandfeel.compareTo(defaultlookandfeel)!=0 ) {
                try {
                    UIManager.setLookAndFeel( defaultlookandfeel );
                } catch ( Throwable e2 ) {
                    e2.printStackTrace();
                }
            }
        }
    }

    /* *********************************************** */
}
